home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / nshellmegasource1.50 / mega src / commands / cp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-23  |  12.0 KB  |  522 lines  |  [TEXT/KAHL]

  1. /* ========== the commmand file: ==========
  2.  
  3.     cp.c
  4.     
  5.     Copyright (c) 1993,1994 Newport Software Development
  6.     
  7.     You may distribute unmodified copies of this file for
  8.     noncommercial purposes.  You may use this file as a
  9.     reference when writing your own nShell(tm) commands.
  10.     
  11.     All other rights are reserved.
  12.     
  13.    ========== the commmand file: ========== */
  14.  
  15. #ifdef __MWERKS__            // CodeWarrior requires an A4 setup
  16. #include <A4Stuff.h>
  17. #endif
  18.  
  19. #define    CP_BUF_SIZE    2048
  20.  
  21. #include <script.h>
  22. #include <string.h>
  23.  
  24. #include "nshc.h"
  25.  
  26. #include "arg_utl.proto.h"
  27. #include "fss_utl.proto.h"
  28. #include "fss_utl2.proto.h"
  29. #include "nshc_utl.proto.h"
  30. #include "str_utl.proto.h"
  31.  
  32. // data definition - this struct is the root of all data
  33.  
  34. typedef enum { copy_none, copy_data, copy_rsrc, copy_close } c_state;
  35.  
  36. typedef struct {
  37.  
  38.     int        got_fss;        // 0 if FSSpec calls are not available
  39.  
  40.     int        arg;            // position in arg list
  41.     
  42.     c_state    copy_state;        // in data or resource portion
  43.     
  44.     Boolean    isDir;            // if target is a directory
  45.     long    dirID;            // id of target if it is a directory
  46.  
  47.     FSSpec    toSpec;            // fsspec of output file
  48.     FSSpec    fromSpec;        // fsspec of input file
  49.     
  50.     short    toData;            // file ref. number, 0 if no file open
  51.     short    toRsrc;            // file ref. number, 0 if no file open
  52.     short    fromData;        // file ref. number, 0 if no file open
  53.     short    fromRsrc;        // file ref. number, 0 if no file open
  54.  
  55. } t_cp_data;
  56.  
  57. typedef    t_cp_data    **CDataH;
  58.  
  59. /* ======================================== */
  60.  
  61. // prototypes - utility
  62.  
  63. void cp_bad( t_nshc_parms *nshc_parms, int code );
  64. void cp_bad_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg );
  65. void cp_good( t_nshc_parms *nshc_parms );
  66.  
  67. // prototypes - file copy routines
  68.  
  69. void cp_setup( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData );
  70. void cp_open( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData );
  71. void cp_read_write( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData );
  72.  
  73. // prototypes - state machine
  74.  
  75. void cp_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls  );
  76. void cp_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  77. void cp_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  78.  
  79. /* ======================================== */
  80.  
  81. // utility routines
  82.  
  83. /* ======================================== */
  84.  
  85. void cp_bad(  t_nshc_parms *nshc_parms, int code )
  86. {
  87.     nshc_parms->action = nsh_stop;
  88.     nshc_parms->result = code;
  89. }
  90.  
  91. void cp_bad_file(  t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg )
  92. {
  93.     nshc_calls->NSH_putStr_err("\pcp: File access error (");
  94.     nshc_calls->NSH_putStr_err(msg);
  95.     nshc_calls->NSH_putStr_err("\p)\r");
  96.  
  97.     nshc_parms->action = nsh_stop;
  98.     nshc_parms->result = NSHC_ERR_GENERAL;
  99. }
  100.  
  101. void cp_good(  t_nshc_parms *nshc_parms )
  102. {
  103.     nshc_parms->action = nsh_stop;
  104.     nshc_parms->result = 0;
  105. }
  106.  
  107. /* ======================================== */
  108.  
  109. // file access routines
  110.  
  111. /* ======================================== */
  112.  
  113. void cp_setup( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData )
  114. {
  115.     int        argc;
  116.     int        result;
  117.     char    *toStr;
  118.     
  119.     // strip off target path and process it
  120.  
  121.     argc = --nshc_parms->argc;
  122.     
  123.     toStr = &nshc_parms->arg_buf[ nshc_parms->argv[argc] ];
  124.     
  125.     if ( cStrEqual( toStr, "dev:tty" ) ) {
  126.         nshc_calls->NSH_putStr_err( "\pcp: \"dev:tty\" is not supported.\r" );
  127.         cp_bad( nshc_parms, NSHC_ERR_PARMS );
  128.         return;
  129.         }
  130.  
  131.     if ( cStrEqual( toStr, "dev:null" ) ) {
  132.         cp_good( nshc_parms );
  133.         return;
  134.         }
  135.         
  136.     result = arg_to_fss( nshc_parms, nshc_calls, argc, &(**hData).toSpec );
  137.     
  138.     if (result)
  139.         cp_bad( nshc_parms, result );
  140.     else{
  141.         result = fss_to_DirID( &(**hData).toSpec, &(**hData).dirID, &(**hData).isDir );
  142.         if (argc > 2)
  143.             if ( (result != noErr) || !(**hData).isDir ) {
  144.                 nshc_calls->NSH_putStr_err( "\pcp: Destination must be a directory when more than one file is copied.\r" );
  145.                 cp_bad( nshc_parms, NSHC_ERR_PARMS );
  146.                 }
  147.         }
  148. }
  149.  
  150. /* ======================================== */
  151.  
  152. void cp_open( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData )
  153. {
  154.     int        result;
  155.     long    dirID;
  156.     Boolean    isDir;
  157.     FInfo    fndrInfo;
  158.     long    newEOF;
  159.     long    oldEOF;
  160.     
  161.     // =====> convert "from" path to fsspec
  162.     
  163.     result = arg_to_fss( nshc_parms, nshc_calls, (**hData).arg, &(**hData).fromSpec );
  164.  
  165.     (**hData).arg++;
  166.     
  167.     if (result) {
  168.         cp_bad( nshc_parms, result );
  169.         return;
  170.         }
  171.     
  172.     result = fss_to_DirID( &(**hData).fromSpec, &dirID, &isDir );
  173.         
  174.     if (( result == noErr) && isDir) {
  175.         nshc_calls->NSH_putStr_err("\pcp: Skiping directory = ");
  176.         nshc_calls->NSH_putStr_err((StringPtr)(**hData).fromSpec.name);
  177.         nshc_calls->NSH_putchar('\r');
  178.         return;
  179.         }
  180.             
  181.     if ( result == fnfErr ) {
  182.         nshc_calls->NSH_putStr_err("\pcp: File not found = ");
  183.         nshc_calls->NSH_putStr_err((StringPtr)(**hData).fromSpec.name);
  184.         nshc_calls->NSH_putchar('\r');
  185.         return;
  186.         }
  187.             
  188.     if ( result ) {
  189.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).fromSpec.name );
  190.         return;
  191.         }
  192.             
  193.     // =====> if "to" is a real file, create it and write finfo
  194.         
  195.     result = fss_GetFInfo((**hData).got_fss, &(**hData).fromSpec, &fndrInfo);
  196.     
  197.     if ( result ) {
  198.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).fromSpec.name );
  199.         return;
  200.         }
  201.  
  202.     if ((**hData).isDir) {
  203.         (**hData).toSpec.parID = (**hData).dirID;
  204.         pStrCopy( (**hData).toSpec.name, (**hData).fromSpec.name );
  205.         }
  206.         
  207.     result =  fss_Delete((**hData).got_fss, &(**hData).toSpec);
  208.     
  209.     if ( ( result != noErr ) && ( result != fnfErr ) ) {
  210.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).toSpec.name );
  211.         return;
  212.         }
  213.  
  214.     result = fss_CreateResFile((**hData).got_fss, &(**hData).toSpec, fndrInfo.fdCreator, fndrInfo.fdType, smSystemScript);
  215.  
  216.     if ( result ) {
  217.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).toSpec.name );
  218.         return;
  219.         }
  220.  
  221.     // =====> open all the file devices
  222.         
  223.     result = fss_OpenDF((**hData).got_fss, &(**hData).fromSpec, fsRdPerm, &(**hData).fromData);
  224.     
  225.     if (!result)
  226.         result = fss_OpenRF((**hData).got_fss, &(**hData).fromSpec, fsRdPerm, &(**hData).fromRsrc);
  227.  
  228.     if (result) {
  229.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).fromSpec.name );
  230.         return;
  231.         }
  232.         
  233.     result = fss_OpenDF((**hData).got_fss, &(**hData).toSpec, fsRdWrShPerm, &(**hData).toData);
  234.  
  235.     if (!result)
  236.         result = fss_OpenRF((**hData).got_fss, &(**hData).toSpec, fsRdWrShPerm, &(**hData).toRsrc);
  237.  
  238.     if (result) {
  239.         cp_bad_file( nshc_parms, nshc_calls, (StringPtr)(**hData).toSpec.name );
  240.         return;
  241.         }
  242.             
  243.     // =====> set the eofs to make sure there is disk space
  244.     // =====> if there is an error, restore the old eofs
  245.     
  246.     if (!result) {        // data fork
  247.     
  248.         result = GetEOF((**hData).toData, &oldEOF);
  249.         
  250.         if (!result)
  251.             result = GetEOF((**hData).fromData, &newEOF);
  252.         
  253.         if (!result)
  254.             result = SetEOF((**hData).toData, newEOF);
  255.     
  256.         if (result)
  257.             SetEOF((**hData).toData, oldEOF);
  258.         }
  259.  
  260.     if (!result) {        // rsrc fork
  261.     
  262.         result = GetEOF((**hData).toRsrc, &oldEOF);
  263.         
  264.         if (!result)
  265.             result = GetEOF((**hData).fromRsrc, &newEOF);
  266.         
  267.         if (!result)
  268.             result = SetEOF((**hData).toRsrc, newEOF);
  269.     
  270.         if (result)
  271.             SetEOF((**hData).toRsrc, oldEOF);
  272.         }
  273.         
  274.     if (result) {
  275.         cp_bad_file( nshc_parms, nshc_calls, "\pend of file" );
  276.         return;
  277.         }
  278.         
  279.     (**hData).copy_state = copy_data;
  280. }
  281.  
  282. /* ======================================== */
  283.  
  284. void cp_read_write( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_cp_data **hData )
  285. {
  286.     int        close;
  287.     int        temp;
  288.     int        result;
  289.     long    bcount;
  290.     char    buf[CP_BUF_SIZE+1];
  291.     
  292.     result = close = 0;
  293.     
  294.     // =====> copy the data fork
  295.     
  296.     if ( (**hData).copy_state == copy_data ) {
  297.     
  298.         bcount = CP_BUF_SIZE;
  299.         result = FSRead( (**hData).fromData, &bcount, &buf );
  300.         
  301.         if (( result == noErr ) || ( result == eofErr )) {
  302.         
  303.             if (result == eofErr) {
  304.                 (**hData).copy_state = copy_rsrc;
  305.                 result = 0;
  306.                 }
  307.             
  308.             if (bcount && !result) {
  309.                 result = FSWrite( (**hData).toData, &bcount, &buf );
  310.                 if (result)
  311.                     cp_bad_file( nshc_parms, nshc_calls, "\pwrite data" );
  312.                 }
  313.             
  314.             }
  315.         else
  316.             cp_bad_file( nshc_parms, nshc_calls, "\pread data" );
  317.         }
  318.     
  319.     // =====> copy the resource fork
  320.     
  321.     if ( (**hData).copy_state == copy_rsrc ) {
  322.     
  323.         bcount = CP_BUF_SIZE;
  324.         result = FSRead( (**hData).fromRsrc, &bcount, &buf );
  325.         
  326.         if (( result == noErr ) || ( result == eofErr )) {
  327.         
  328.             if (result == eofErr) {
  329.                 (**hData).copy_state = copy_close;
  330.                 result = 0;
  331.                 }
  332.             
  333.             if (bcount && !result) {
  334.                 result = FSWrite( (**hData).toRsrc, &bcount, &buf );
  335.                 if (result)
  336.                     cp_bad_file( nshc_parms, nshc_calls, "\pwrite resource" );
  337.                 }
  338.             
  339.             }
  340.         else
  341.             cp_bad_file( nshc_parms, nshc_calls, "\pread resource" );
  342.  
  343.         }
  344.     
  345.     // =====> close the input file
  346.     
  347.     if ( (**hData).copy_state == copy_close ) {
  348.  
  349.         if ( (**hData).fromData ) {
  350.             if ( temp = FSClose( (**hData).fromData ) )
  351.                 result = temp;
  352.             (**hData).fromData = 0;
  353.             }
  354.     
  355.         if ( (**hData).fromRsrc ) {
  356.             if ( temp = FSClose( (**hData).fromRsrc ) )
  357.                 result = temp;
  358.             (**hData).fromRsrc = 0;
  359.             }
  360.     
  361.         if ( (**hData).toData ) {
  362.             if ( temp = FSClose( (**hData).toData ) )
  363.                 result = temp;
  364.             (**hData).toData = 0;
  365.             }
  366.     
  367.         if ( (**hData).toRsrc ) {
  368.             if ( temp = FSClose( (**hData).toRsrc ) )
  369.                 result = temp;
  370.             (**hData).toRsrc = 0;
  371.             }
  372.         
  373.         (**hData).copy_state = copy_none;
  374.         
  375.         if (result)
  376.             cp_bad_file( nshc_parms, nshc_calls, "\pclose file" );
  377.         
  378.         }
  379. }
  380.  
  381. /* ======================================== */
  382.  
  383. // state machine - core routines
  384.  
  385. /* ======================================== */
  386.  
  387. void cp_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls  )
  388. {
  389.     CDataH    hData;    // handle to hold our data
  390.     
  391.     if (nshc_parms->argc < 3) {
  392.         nshc_calls->NSH_putStr_err( "\pUsage: see \"man cp\" for options.\r" );
  393.         cp_bad( nshc_parms, NSHC_ERR_PARMS );
  394.         return;
  395.         }
  396.         
  397.     nshc_parms->action = nsh_continue;
  398.  
  399.     hData = (CDataH)NewHandleClear(sizeof(t_cp_data));
  400.     
  401.     if (hData) {
  402.         (**hData).arg = 1;                    // start at the arg = 1 position
  403.         (**hData).got_fss = fss_test();        // test if we can use FSSpec calls
  404.         nshc_parms->data = (Handle)hData;
  405.         HLock( (Handle)hData );
  406.         cp_setup( nshc_parms, nshc_calls, hData );
  407.         HUnlock( (Handle)hData );
  408.         }
  409.     else {
  410.         nshc_calls->NSH_putStr_err( "\pcp: Could not allocate storage.\r" );
  411.         cp_bad( nshc_parms, NSHC_ERR_MEMORY );
  412.         }
  413. }
  414.  
  415. /* ======================================== */
  416.  
  417. void cp_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  418. {
  419.     CDataH    hData;
  420.     
  421.     if (hData = (CDataH)nshc_parms->data) {
  422.  
  423.         if ((**hData).copy_state == copy_none) {
  424.         
  425.             if ((**hData).arg >= nshc_parms->argc) {
  426.                 cp_good( nshc_parms );
  427.                 return;
  428.                 }
  429.     
  430.             HLock( (Handle)hData );
  431.             cp_open( nshc_parms, nshc_calls, hData );
  432.             HUnlock( (Handle)hData );
  433.             }
  434.         
  435.         if ((**hData).copy_state != copy_none) {
  436.         
  437.             HLock( (Handle)hData );
  438.             cp_read_write( nshc_parms, nshc_calls, hData );
  439.             HUnlock( (Handle)hData );
  440.             
  441.             }
  442.         }
  443. }
  444.  
  445. /* ======================================== */
  446.  
  447. void cp_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  448. {
  449.     short    fRef;
  450.     OSErr    error;
  451.     CDataH    hData;
  452.     int        temp;
  453.     int        result;
  454.     
  455.     result = 0;
  456.     
  457.     if (hData = (CDataH)nshc_parms->data) {
  458.     
  459.         if ( (**hData).fromData ) {
  460.             if ( temp = FSClose( (**hData).fromData ) )
  461.                 result = temp;
  462.             (**hData).fromData = 0;
  463.             }
  464.     
  465.         if ( (**hData).fromRsrc ) {
  466.             if ( temp = FSClose( (**hData).fromRsrc ) )
  467.                 result = temp;
  468.             (**hData).fromRsrc = 0;
  469.             }
  470.     
  471.         if ( (**hData).toData ) {
  472.             if ( temp = FSClose( (**hData).toData ) )
  473.                 result = temp;
  474.             (**hData).toData = 0;
  475.             }
  476.     
  477.         if ( (**hData).toRsrc ) {
  478.             if ( temp = FSClose( (**hData).toRsrc ) )
  479.                 result = temp;
  480.             (**hData).toRsrc = 0;
  481.             }
  482.         
  483.         DisposeHandle(nshc_parms->data);
  484.         }
  485.         
  486.     if (result)
  487.         cp_bad_file( nshc_parms, nshc_calls, "\pclosing files" );
  488.         
  489.     nshc_parms->action = nsh_idle;
  490. }
  491.  
  492. /* ======================================== */
  493.  
  494. void main(t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls)
  495. {
  496. #ifdef __MWERKS__
  497.     long oldA4  = SetCurrentA4();
  498. #endif
  499.     
  500.     if ( !nshc_bad_version( nshc_parms, nshc_calls, NSHC_VERSION ) ) {
  501.     
  502.         switch (nshc_parms->action) {
  503.             case nsh_start:
  504.                 cp_start(nshc_parms, nshc_calls);
  505.                 break;
  506.             case nsh_continue:
  507.                 cp_continue(nshc_parms, nshc_calls);
  508.                 break;
  509.             case nsh_stop:
  510.                 cp_stop(nshc_parms, nshc_calls);
  511.                 break;
  512.             }
  513.             
  514.         }
  515.     
  516. #ifdef __MWERKS__
  517.     SetA4(oldA4);
  518. #endif
  519. }
  520.  
  521. /* ======================================== */
  522.